package com.xxl.job.executor.utils;

public class ByteUtil {

    private static final char[] DIGITS_LOWER;
    private static final char[] DIGITS_UPPER;

    static {
        DIGITS_LOWER = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        DIGITS_UPPER = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    }

    public static String hexStringToString(String s) {
        if (s == null || s.equals("")) {
            return null;
        }
        s = s.replace("00", "");
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            s = new String(baKeyword, "utf-8");
            new String();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return s;
    }

    public static String str2HexStr(String str,int lenth){
        StringBuilder sb = new StringBuilder();
        int i;
        byte[] bs = str.getBytes();
        for (i = 0; i < bs.length; i++){
            sb.append(DIGITS_UPPER[(bs[i] & 0xFF) >> 4]);
            sb.append(DIGITS_UPPER[bs[i] & 0x0F]);
        }
        for(int j = i;j<lenth;j++){
            sb.append('0');
            sb.append('0');
        }
        return sb.toString().trim();
    }

    public static String bytes2hexStr(byte[] bytes) {
        return new String(bytes2hexChar(bytes));
    }

    public static String bytes2hexStr(byte[] bytes, int offset, int length) {
        return new String(bytes2hexChar(bytes, offset, length));
    }

    public static char[] bytes2hexChar(byte[] data) {
        return bytes2hexChar(data, 0, data.length, true);
    }

    public static char[] bytes2hexChar(byte[] data, int offset, int length) {
        return bytes2hexChar(data, offset, length, false);
    }

    public static char[] bytes2hexChar(byte[] data, int offset, int length, boolean toLowerCase) {
        return bytes2hexChar(data, offset, length, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
    }

    public static char[] bytes2hexChar(byte[] data, int offset, int length, char[] toDigits) {
        char[] out = new char[length << 1];

        for (int i = offset, j = 0; j < out.length; ++i) {
            out[j++] = toDigits[(240 & data[i]) >>> 4];
            out[j++] = toDigits[15 & data[i]];
        }

        return out;
    }

    public static byte[] hexStr2bytes(String data) {
        return hexChars2bytes(data.toCharArray());
    }

    public static byte[] hexChars2bytes(char[] data) {
        int len = data.length;
        if ((len & 1) != 0) {
            throw new RuntimeException("Odd number of characters.");
        } else {
            byte[] out = new byte[len >> 1];
            int i = 0;

            for (int j = 0; j < len; ++i) {
                int f = toDigit(data[j], j) << 4;
                ++j;
                f |= toDigit(data[j], j);
                ++j;
                out[i] = (byte) (f & 255);
            }

            return out;
        }
    }

    public static int toDigit(char ch, int index) {
        int digit = Character.digit(ch, 16);
        if (digit == -1) {
            throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index);
        } else {
            return digit;
        }
    }

    public static String bytes2ip(byte[] sn) {
        return ByteUtil.bytes2int(sn,0,1) + "." + ByteUtil.bytes2int(sn,1,1) + "." + ByteUtil.bytes2int(sn,2,1) + "." + ByteUtil.bytes2int(sn,3,1);
    }

    public static byte[] ip2bytes(String sIp){
        String[] ss = sIp.split("\\.");
        if(ss.length != 4){
            throw new RuntimeException("Illegal IP:"+sIp);
        }
        byte[] byteIp = new byte[4];
        for(int i=0;i<ss.length;i++){
            byteIp[i] =  (byte) Integer.parseInt(ss[i]);
        }
        return byteIp;
    }

    public static int bytes2int(byte[] src, int offset) {
        return bytes2int(src, offset, 4);
    }

    public static int bytes2int(byte[] src, int offset, int length) {
        int value = 0;
        for (int i = 0; i < length; i++) {
            value = value | ((src[offset + i] & 0xFF) << (length - i - 1) * 8);
        }
        return value;
    }

    public static byte[] int2bytes(int v) {
        return int2bytes(v, 4);
    }

    public static byte[] int2bytes(int v, int length) {
        byte[] bytes = new byte[length];
        for (int i = 0; i < length; i++) {
            if (i < length - 1) {
                bytes[i] = (byte) (v >>> ((length - 1 - i) * 8) & 0xff);
            } else {
                bytes[i] = (byte) (v & 0xff);
            }
        }
        return bytes;
    }
    

    /**
     * 以小端模式将int转成byte[]
     *
     * @param value
     * @return
     */
    public static byte[] int2BytesLittle(int value,int length) {
        byte[] src = new byte[length];
        for (int i = 0; i < length; i++) {
           if (i>0) {
         	  src[i] = (byte) (value >>> (i * 8) & 0xff);
           } else {
         	  src[i] = (byte) (value & 0xff);
           }
       }
        return src;
    }


    /**
     * 以小端模式将byte[]转成int
     */
    public static int bytes2IntLittle(byte[] src, int offset) {
   	 return bytes2IntLittle(src, offset, 4);
    }
    
    public static int bytes2IntLittle(byte[] src, int offset,int length) {
   	 int value = 0;
       for (int i = 0; i < length; i++) {
           value = value | ((src[offset + i] & 0xFF) << i * 8);
       }
        return value;
    }

    public static int generateCode(int b) {
        return (~(((b & 0xf) + (b >>> 4 & 0xf) + (b >>> 8 & 0xf)) % 16) + 1) & 0xf;
    }

    public static int generateCode(byte[] bytes) {
        int sum = 0;
        for (byte b : bytes) {
            sum += b;
        }
        return ~(sum % 65536) + 1;
    }

    // 长度校验码检验
    public static boolean checkLength(int b) {
        return (b >>> 12 & 0xf) == ((~(((b & 0xf) + (b >>> 4 & 0xf) + (b >>> 8 & 0xf)) % 16) + 1) & 0xf);
    }

    // 校验和检验
    public static boolean checkCode(byte[] bytes, int code) {
        int sum = 0;
        for (byte b : bytes) {
            sum += b;
        }
        return code == ~(sum % 65536) + 1;
    }
    
    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2){  
       byte[] byte_3 = new byte[byte_1.length+byte_2.length];  
       System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);  
       System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);  
       return byte_3;  
   }

    public static float getFloat(byte[] b) {
        int accum = 0;
        accum = accum|(b[0] & 0xff) << 0;
        accum = accum|(b[1] & 0xff) << 8;
        accum = accum|(b[2] & 0xff) << 16;
        accum = accum|(b[3] & 0xff) << 24;
        return Float.intBitsToFloat(accum);
    }
}
